home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / utils / mmgr / pg_malloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-06  |  29.5 KB  |  1,182 lines

  1. #include "tmp/c.h"
  2.  
  3. RcsId("$Header: /private/postgres/src/utils/mmgr/RCS/pg_malloc.c,v 1.8 1991/11/12 20:20:29 mer Exp $");
  4.  
  5. #include "access/htup.h"
  6. #include "utils/memutils.h"
  7. #include "utils/log.h"
  8. #include "utils/pg_malloc.h"
  9.  
  10. #include "nodes/pg_lisp.h"
  11.  
  12. static bool8 memory_is_initialized = FALSE;
  13. static int number_of_nodes = 0;
  14. extern struct nodeinfo _NodeInfo[]; 
  15.  
  16. static MemoryPageData xact_page_data = {NULL, 0, NULL, NULL, NULL};
  17. static MemoryPageData global_page_data = {NULL, 0, NULL, NULL, NULL};
  18.  
  19. static MemoryPageData *page_data = &xact_page_data;
  20.  
  21. static bool8 memory_tracing_mode = FALSE;
  22. static uint8 trace_depth = 0;
  23.  
  24. static NodeTable *node_table = NULL;
  25.  
  26. #undef HeaderIsValid
  27. #define HeaderIsValid(header) \
  28.     ((header) != NULL \
  29.      && (header)->sanity_check == (long) (header) + sizeof(*(header)))
  30.  
  31. #undef PageIsValid
  32. #define PageIsValid(page) \
  33.     (((page) != NULL) && ((page)->sanity_check == (long) (page)->begin_addr))
  34.  
  35. #undef NextOtherHeader
  36. #define NextOtherHeader(header) \
  37.     ((OtherMemoryHeader *) (((long) (header)) \
  38.      + sizeof(OtherMemoryHeader) + (header)->size))
  39.  
  40. #undef NextNodeHeader(header,
  41. #define NextNodeHeader(header, size) \
  42.     ((NodeMemoryHeader *) (((long) (header)) \
  43.      + sizeof(NodeMemoryHeader) + size))
  44.  
  45. #undef NodeTableHash
  46. #define NodeTableHash(size) \
  47.     ((LONGALIGN(size) - PALLOC_HEADER_SIZE) / 4 - 1)
  48.  
  49. #undef SizeIsNodeSize
  50. #define SizeIsNodeSize(size) \
  51.     (NodeTableHash(size) > -1 && NodeTableHash(size) < number_of_nodes)
  52. /*
  53.  *******************************
  54.  * EXTERNAL INTERFACE ROUTINES *
  55.  *******************************
  56.  */
  57.  
  58. unsigned char *
  59. pg_malloc(size)
  60.  
  61. Size size;
  62.  
  63. {
  64.     unsigned char *retval = NULL;
  65.  
  66.     if (!memory_is_initialized) {
  67.         InitMemoryPages();
  68.         memory_is_initialized = TRUE;
  69.     }
  70.  
  71. /*
  72.  * Force all returned addresses to be on long boundaries.
  73.  */
  74.  
  75.     size = LONGALIGN(size);
  76.  
  77. /*
  78.  * GetNodeMemory returns NULL if size is not really a node size
  79.  */
  80.  
  81.     if (SizeIsNodeSize(size)) retval = GetNodeMemory(size);
  82.  
  83. /*
  84.  * GetOtherMemory returns NULL if size is too big to fit into a page
  85.  */
  86.  
  87.     if (retval == NULL) retval = GetOtherMemory(size);
  88.  
  89.     if (retval == NULL) retval = GetBigMemory(size);
  90.  
  91.     return(retval);
  92. }
  93.  
  94. pg_free(addr)
  95.  
  96. unsigned char *addr;
  97.  
  98. {
  99.     if (FreeNodeMemory(addr))
  100.         return;
  101.     else if (FreeOtherMemory(addr))
  102.         return;
  103.     else if (FreeBigMemory(addr))
  104.         return;
  105.     else
  106.     {
  107.         elog(NOTICE, "Address %x was not allocated with pg_malloc", addr);
  108.         elog(NOTICE, "Address will be freed using free()");
  109.         free((char *)addr);
  110.         return;
  111.     }
  112. }
  113.  
  114. /*
  115.  * Zeros out all the pages.  It frees all the pages which were allocated with
  116.  * malloc and initializes all others.
  117.  */
  118.  
  119. pg_zero_memory()
  120.  
  121. {
  122.     NodeMemoryPage *npage, *ntrailer;
  123.     OtherMemoryPage *opage, *otrailer;
  124.     BigMemoryPage *bpage, *btrailer;
  125.  
  126.     int i;
  127.  
  128.     for (i = 0; i < number_of_nodes; i++)
  129.     {
  130.         if (xact_page_data.node_table[i].used)
  131.         {
  132.             for (npage = npage = xact_page_data.node_table[i].first_page;
  133.                  npage != NULL;
  134.                  npage = npage->next)
  135.             {
  136.                 if (npage->is_malloced)
  137.                 {
  138.                     ntrailer->next = npage->next;
  139.                     free((char *)npage);
  140.                     npage = ntrailer;
  141.                 }
  142.                 else
  143.                 {
  144.                     npage->ref_count = 0;
  145.                     npage->page_full = FALSE;
  146.                     bzero(npage->page_map, MAPSIZE);
  147.                 }
  148.                 ntrailer = npage;
  149.             }
  150.         }
  151.     }
  152.  
  153.     for (opage = xact_page_data.other_pages;
  154.          opage != NULL;
  155.          opage = opage->next)
  156.     {
  157.         if (opage->is_malloced)
  158.         {
  159.             otrailer->next = opage->next;
  160.             free((char *)opage);
  161.             opage = otrailer;
  162.         }
  163.         else
  164.         {
  165.             opage->ref_count = 0;
  166.             opage->total = 0;
  167.             opage->working_addr = opage->begin_addr;
  168.             opage->page_full = FALSE;
  169.             opage->biggest_free_object = 0;
  170.         }
  171.     }
  172.  
  173.     if (xact_page_data.big_pages != NULL)
  174.     {
  175.         for (bpage = xact_page_data.big_pages;
  176.              bpage->next != NULL; /* do nothing */ )
  177.         {
  178.             btrailer = bpage->next;
  179.             free((char *)bpage);
  180.             bpage=btrailer;
  181.         }
  182.         free((char *)bpage);
  183.  
  184.         xact_page_data.big_pages = NULL;
  185.     }
  186. }
  187.  
  188. /*
  189.  ********************
  190.  * PRIVATE ROUTINES *
  191.  ********************
  192.  */
  193.  
  194. /*
  195.  ****************
  196.  * INITIALIZERS *
  197.  ****************
  198.  */
  199.  
  200. /*
  201.  * This routine initializes the predefined memory pages.
  202.  */
  203.  
  204. InitMemoryPages()
  205.  
  206. {
  207.     NodeMemoryPage *scanner;
  208.     OtherMemoryPage *other_scanner;
  209.     NodeTable *node_table;
  210.     long i, j;
  211.     bool8 entering = TRUE;
  212.     Size size;
  213.  
  214.     xact_page_data.total_size = PAGE_SIZE * PAGES_ALLOCATED;
  215.     xact_page_data.space_used = 0;
  216.     xact_page_data.my_space = (unsigned char *)
  217.                               malloc(xact_page_data.total_size);
  218.     if (xact_page_data.my_space == NULL) {
  219.         perror("malloc");
  220.         elog(WARN, "Memory manager (InitMemoryPages) - MALLOC FAILED");
  221.     }
  222.  
  223. /*
  224.  * Initialize the first table of memories
  225.  */
  226.  
  227.     node_table = InitializeNodeTable();
  228.  
  229.     for (i = 0; i < number_of_nodes; i++)
  230.     {
  231.         if (node_table[i].used)
  232.         {
  233.             node_table[i].first_page = AllocateNodePage(node_table[i].size);
  234.             scanner = node_table[i].first_page;
  235.             for (j = 1; j < node_table[i].page_count; j++)
  236.             {
  237.                 scanner->next = AllocateNodePage(node_table[i].size);
  238.                 scanner = scanner->next;
  239.             }
  240.         }
  241.     }
  242.  
  243.     xact_page_data.node_table = node_table;
  244.  
  245.     entering = TRUE;
  246.     for (i = 0; i < TOTAL_NONNODE_PAGES; i++)
  247.     {
  248.         if (entering)
  249.         {
  250.             xact_page_data.other_pages = AllocateOtherPage();
  251.             other_scanner = xact_page_data.other_pages;
  252.             entering = FALSE;
  253.         }
  254.         else
  255.         {
  256.             other_scanner->next = AllocateOtherPage();
  257.             other_scanner = other_scanner->next;
  258.         }
  259.     }
  260.     xact_page_data.big_pages = NULL;
  261. }
  262.  
  263. /*
  264.  * This routine initializes the node page information - it cannot use
  265.  * elog because it is called too early and elog aborts.
  266.  *
  267.  * Eventually, the heuristics for memory usage will be passed as an
  268.  * argument.
  269.  */
  270.  
  271. NodeTable *
  272. InitializeNodeTable()
  273.  
  274. {
  275.     int i, j, position, size;
  276.     NodeTable *node_table;
  277.  
  278.     for (i = 0; _NodeInfo[i].ni_size != 0; i++);
  279.     number_of_nodes = i;
  280.  
  281.     node_table = (NodeTable *) malloc(number_of_nodes * sizeof(NodeTable));
  282.  
  283.     for (i = 0; i < number_of_nodes; i++)
  284.     {
  285.         node_table[i].used = FALSE;
  286.         node_table[i].node_count = 0;
  287.         node_table[i].names = NULL;
  288.         node_table[i].size = 0;
  289.         node_table[i].page_count = 0;
  290.         node_table[i].first_page = NULL;
  291.     }
  292.  
  293.     for (i = 0; i < number_of_nodes; i++)
  294.     {
  295.         size = _NodeInfo[i].ni_size + PALLOC_HEADER_SIZE;
  296.         position = NodeTableHash(size);
  297.         if (position >= number_of_nodes)
  298.         {
  299.             /*
  300.              * These were sprintf(stderr, ...) and were never ever
  301.              * correct. (kai)
  302.              */
  303.             fprintf(stderr, "InitializeNodeTable - hash failed for %s",
  304.                     _NodeInfo[i].ni_name);
  305.             fprintf(stderr, "Non-node memory will be used.");
  306.         }
  307.         else
  308.         {
  309.             if (!node_table[position].used) node_table[position].used = TRUE;
  310.             node_table[position].node_count += 1;
  311.             node_table[position].size = LONGALIGN(size);
  312. /*
  313.  * This should be assigned to the right value once we start doing memory
  314.  * heuristics.  For now, we will just count the number of nodes of the
  315.  * same size, and allocate that many pages per node.
  316.  */
  317.  
  318.             node_table[position].page_count += 1;
  319.         }
  320.     }
  321.  
  322. /* 
  323.  * Now we set up the name table information for use by the trace functions.
  324.  */
  325.  
  326.     for (i = 0; i < number_of_nodes; i++)
  327.     {
  328.         size = _NodeInfo[i].ni_size + PALLOC_HEADER_SIZE;
  329.         position = NodeTableHash(size);
  330.         if (node_table[position].names == NULL)
  331.         {
  332.             size = node_table[position].node_count * sizeof(char *);
  333.             node_table[position].names = (char **) malloc(size);
  334.             for (j = 0; j < node_table[position].node_count; j++)
  335.                 node_table[position].names[j] = NULL;
  336.         }
  337.         for (j = 0; node_table[position].names[j] != NULL; j++);
  338.  
  339.         size = strlen(_NodeInfo[i].ni_name) + 1;
  340.         node_table[position].names[j] = (char *) malloc(size);
  341.         strcpy(node_table[position].names[j], _NodeInfo[i].ni_name);
  342.     }
  343.     return(node_table);
  344. }
  345.  
  346. unsigned char *
  347. GetNodeMemory(size)
  348.  
  349. Size size;
  350.  
  351. {
  352.     NodeMemoryPage *scanner, *last_page, *this_page;
  353.     NodeMemoryHeader *header;
  354.     unsigned char *addr = NULL;
  355.     bool8 size_is_node_size = FALSE;
  356.     int offset, i, j, hash_position;
  357.  
  358. /*
  359.  * See if the hash table entry for this size is really a node.  If it is,
  360.  * find the first page with free elements in it.  Then compute the address.
  361.  */
  362.  
  363.     hash_position = NodeTableHash(size);
  364.  
  365.     if (!page_data->node_table[hash_position].used) return(NULL);
  366.  
  367.     for (scanner = page_data->node_table[hash_position].first_page;
  368.          scanner != NULL && addr == NULL;
  369.          scanner = scanner->next)
  370.     {
  371.         if (!PageIsValid(scanner)) {
  372.             elog(WARN, "GetNodeMemory - page at %x corrupted!", scanner);
  373.         }
  374.  
  375.         if (scanner->element_size == size && !scanner->page_full)
  376.         {
  377.             header = scanner->first_free_header;
  378.             addr = (unsigned char *)
  379.                    ((long) header + sizeof(NodeMemoryHeader));
  380.             header->debug_depth = trace_depth;
  381.             SetElement(scanner->page_map);
  382.             scanner->ref_count += 1;
  383.             SetNextFreeNode(scanner, scanner->offset);
  384.             this_page = scanner;
  385.         }
  386. /*
  387.  * In case we have to allocate a new page, set last_page to scanner.
  388.  */
  389.         if (scanner->next == NULL) last_page = scanner;
  390.     }
  391.  
  392.     if (addr != NULL)
  393.     {
  394.         if (this_page->ref_count == this_page->max_elements)
  395.         {
  396.             this_page->page_full = TRUE;
  397.             this_page->first_free_header = NULL;
  398.         }
  399.     }
  400.  
  401. /*
  402.  * Here we have to allocate a new page and we set this object to the first
  403.  * element of the new page.
  404.  */
  405.  
  406.     if (addr == NULL)
  407.     {
  408.         last_page->next = AllocateNodePage(size);
  409.         this_page = last_page->next;
  410.         this_page->page_map[0] = SET_BIT(this_page->page_map[0], 0);
  411.         header = (NodeMemoryHeader *) this_page->begin_addr;
  412.         addr = this_page->begin_addr + sizeof(NodeMemoryHeader);
  413.         header->debug_depth = trace_depth;
  414.         this_page->ref_count = 1;
  415.         this_page->first_free_header = (NodeMemoryHeader *)
  416.                                        ((long) header
  417.                                         + sizeof(NodeMemoryHeader)
  418.                                         + this_page->element_size);
  419.         this_page->offset = 1;
  420.     }
  421.     return(addr);
  422. }
  423.  
  424. unsigned char *
  425. GetOtherMemory(size)
  426.  
  427. Size size;
  428.  
  429. {
  430.     OtherMemoryPage *page, *last_page, *this_page;
  431.     OtherMemoryHeader *header, *scanhdr;
  432.     unsigned char *addr = NULL, scan_addr;
  433.     int offset, i;
  434.  
  435.     if (size > PAGE_SIZE - sizeof(OtherMemoryPage) - sizeof(char)) return(NULL);
  436.  
  437.     for (page = page_data->other_pages;
  438.          page != NULL && addr == NULL;
  439.          page = page->next)
  440.     {
  441.  
  442.         if (!page->page_full)
  443.         {
  444.             if (page->biggest_free_object >= size)
  445.             {
  446.                 if (page->first_free_header->size >= size)
  447.                 {
  448.                     header = page->first_free_header;
  449.                     if (page->total - page->ref_count > 1) /* at least one */
  450.                     {
  451.                         scanhdr = NextOtherHeader(header);
  452.                         while (scanhdr->used)
  453.                         {
  454.                             if (!HeaderIsValid(scanhdr))
  455.                             {
  456.                                 other_memory_page_info(page);
  457.                                 elog(WARN, "GetOtherMemory: page corrupted!");
  458.                             }
  459.                             scanhdr = NextOtherHeader(scanhdr);
  460.                         }
  461.                         page->first_free_header = scanhdr;
  462.                     }
  463.                 }
  464.                 else
  465.                 {
  466.                     scanhdr = page->first_free_header;
  467.                     while (scanhdr->used || scanhdr->size < size)
  468.                     {
  469.                         scanhdr = NextOtherHeader(scanhdr);
  470.                         if (!HeaderIsValid(scanhdr))
  471.                         {
  472.                             other_memory_page_info(page);
  473.                             elog(WARN, "GetOtherMemory: page corrupted!");
  474.                         }
  475.                     }
  476.                     header = scanhdr;
  477.                 }
  478.                 if (!HeaderIsValid(header))
  479.                     elog(WARN, "GetOtherMemory: page corrupted!");
  480.                 page->ref_count += 1;
  481.                 header->used = TRUE;
  482.                 addr = (unsigned char *) header + sizeof(OtherMemoryHeader);
  483.  
  484.                 if (page->ref_count == page->total)
  485.                 {
  486.                     page->first_free_header = NULL;
  487.                     page->biggest_free_object = 0;
  488.                 }
  489.                 else if (header->size == page->biggest_free_object)
  490.                 {
  491.                     page->biggest_free_object = LargestFreeObject(page);
  492.                     if (page->biggest_free_object == 0)
  493.                     {
  494.                         other_memory_page_info(page);
  495.                         elog (WARN, "GetOtherMemory: free object scan failed");
  496.                     }
  497.                 }
  498.                 this_page = page;
  499.             }
  500.             else if (page->working_addr + size + sizeof(OtherMemoryHeader)
  501.               < page->end_addr)
  502.             {
  503.                 header = (OtherMemoryHeader *) page->working_addr;
  504.                 header->sanity_check = (long) header
  505.                                      + sizeof(OtherMemoryHeader);
  506.                 header->size = size;
  507.                 header->used = TRUE;
  508.                 header->debug_depth = trace_depth;
  509.                 addr = page->working_addr + sizeof(OtherMemoryHeader);
  510.                 page->ref_count += 1;
  511.                 page->total += 1;
  512.                 page->working_addr += size + sizeof(OtherMemoryHeader);
  513.                 page->last_header = header;
  514.                 this_page = page;
  515.             }
  516.         }
  517.         if (page->next == NULL) last_page = page;
  518.     }
  519.  
  520. /*
  521.  * Here we need to allocate a new page
  522.  */
  523.  
  524.     if (addr == NULL)
  525.     {
  526.         last_page->next = AllocateOtherPage();
  527.         this_page = last_page->next;
  528.         header = (OtherMemoryHeader *) this_page->begin_addr;
  529.         header->sanity_check = (long) header + sizeof(OtherMemoryHeader);
  530.         header->size = size;
  531.         header->used = TRUE;
  532.         header->debug_depth = trace_depth;
  533.         this_page->last_header = header;
  534.         this_page->total = this_page->ref_count = 1;
  535.         this_page->working_addr = this_page->begin_addr
  536.                            + size + sizeof(OtherMemoryHeader);
  537.         addr = (unsigned char *) header + sizeof(OtherMemoryHeader);
  538.     }
  539.  
  540. /*
  541.  * Here we figure out if the page is full.
  542.  */
  543.     if ((this_page->end_addr - this_page->working_addr <
  544.         sizeof(OtherMemoryHeader) + 1)
  545.      && (this_page->total == this_page->ref_count))
  546.     {
  547.         this_page->page_full = TRUE;
  548.     }
  549.     return(addr);
  550. }
  551.  
  552. unsigned char *
  553. GetBigMemory(size)
  554.  
  555. Size size;
  556.  
  557. {
  558.     BigMemoryPage *page;
  559.  
  560.     if (page_data->big_pages == NULL)
  561.     {
  562.         page = page_data->big_pages = AllocateBigPage(size);
  563.     }
  564.     else
  565.     {
  566.         for (page = page_data->big_pages;
  567.              page->next != NULL;
  568.              page = page->next);
  569.         page->next = AllocateBigPage(size);
  570.         page = page->next;
  571.     }
  572.     return((unsigned char *) &(page->memory[0]));
  573. }
  574.  
  575. /*
  576.  ***********************
  577.  * ALLOCATION ROUTINES *
  578.  ***********************
  579.  */
  580.  
  581. /*
  582.  * This could handle end of page overruns in a smarter way, but we'll get
  583.  * this to work first.
  584.  */
  585.  
  586. NodeMemoryPage *
  587. AllocateNodePage(element_size)
  588.  
  589. Size element_size;
  590.  
  591. {
  592.     NodeMemoryPage *page;
  593.     int i, total_element_size;
  594.     NodeMemoryHeader *header;
  595.  
  596.     if (page_data->space_used + PAGE_SIZE > page_data->total_size)
  597.     {
  598.         page = (NodeMemoryPage *) malloc(PAGE_SIZE);
  599.         if (page == NULL)
  600.         {
  601.             perror("malloc");
  602.             elog(WARN, "Memory manager (AllocateNodePage) - MALLOC FAILED");
  603.         }
  604.         page->is_malloced = TRUE;
  605.     }
  606.     else
  607.     {
  608.         page = (NodeMemoryPage *) (page_data->my_space + page_data->space_used);
  609.         page_data->space_used += PAGE_SIZE;
  610.         page->is_malloced = FALSE;
  611.     }
  612.     page->ref_count = 0;
  613.     page->begin_addr = &(page->memory[0]);
  614.     page->end_addr = (unsigned char *) page + PAGE_SIZE - 1;
  615.     page->element_size = element_size;
  616.     total_element_size = element_size + sizeof(NodeMemoryHeader);
  617.     page->max_elements = (page->end_addr - page->begin_addr)
  618.                        / total_element_size;
  619.  
  620.     for (i = 0, header = (NodeMemoryHeader *) page->begin_addr;
  621.          i < page->max_elements;
  622.          i++, header = NextNodeHeader(header, element_size))
  623.     {
  624.         header->sanity_check = (long) header + sizeof(NodeMemoryHeader);
  625.         header->debug_depth = 0;
  626.         header->size = element_size;
  627.     }
  628.  
  629.     if (page->max_elements > MAPSIZE * BITS_IN_BYTE)
  630.         page->max_elements = MAPSIZE * BITS_IN_BYTE;
  631.  
  632.     page->page_full = FALSE;
  633.     bzero(page->page_map, MAPSIZE);
  634.     page->next = NULL;
  635.     page->sanity_check = (long) (page->begin_addr);
  636.     page->first_free_header = (NodeMemoryHeader *) page->begin_addr;
  637.     return(page);
  638. }
  639.  
  640. OtherMemoryPage *
  641. AllocateOtherPage()
  642.  
  643. {
  644.     OtherMemoryPage *page;
  645.     OtherMemoryHeader *header;
  646.  
  647.     if (page_data->space_used + PAGE_SIZE > page_data->total_size)
  648.     {
  649.         page = (OtherMemoryPage *) malloc(PAGE_SIZE);
  650.         if (page == NULL)
  651.         {
  652.             perror("malloc");
  653.             elog(WARN, "Memory manager (AllocateOtherPage) - MALLOC FAILED");
  654.         }
  655.         page->is_malloced = TRUE;
  656.     }
  657.     else
  658.     {
  659.         page = (OtherMemoryPage *)
  660.                (page_data->my_space + page_data->space_used);
  661.  
  662.         page_data->space_used += PAGE_SIZE;
  663.         page->is_malloced = FALSE;
  664.     }
  665.     page->page_full = FALSE;
  666.  
  667.     page->ref_count = page->total = 0;
  668.     page->biggest_free_object = 0;
  669.     page->first_free_header = page->last_header = NULL;
  670.  
  671.     page->begin_addr = page->working_addr = &(page->memory[0]);
  672.     page->end_addr = (unsigned char *) page + PAGE_SIZE - 1;
  673.     page->next = NULL;
  674.     page->sanity_check = (long) (page->begin_addr);
  675.     return(page);
  676. }
  677.  
  678. BigMemoryPage *
  679. AllocateBigPage(size)
  680.  
  681. Size size;
  682.  
  683. {
  684.     BigMemoryPage *page;
  685.     Size page_size;
  686.  
  687.     page_size = sizeof(BigMemoryPage) + size - sizeof(char *);
  688.  
  689.     page = (BigMemoryPage *) malloc(page_size);
  690.     if (page == NULL)
  691.     {
  692.         perror("malloc");
  693.         elog(WARN, "Memory manager (AllocateBigPage) - MALLOC FAILED");
  694.     }
  695.     page->begin_addr = &(page->memory[0]);
  696.     page->end_addr = (unsigned char *) page->begin_addr + size - 1;
  697.     page->next = NULL;
  698.     page->sanity_check = (long) (page->begin_addr);
  699.     page->header.sanity_check = (long) page->begin_addr;
  700.     page->header.size = 32767;
  701.     page->header.used = TRUE;
  702.     page->header.debug_depth = trace_depth;
  703.     return(page);
  704. }
  705.  
  706. /*
  707.  ********************
  708.  * FREEING ROUTINES *
  709.  ********************
  710.  */
  711.  
  712. bool8
  713. FreeNodeMemory(addr)
  714.  
  715. unsigned char *addr;
  716.  
  717. {
  718.     NodeMemoryPage *page, *prev = NULL;
  719.     NodeMemoryHeader *header;
  720.     int offset, index, bit, hash_position;
  721.     bool8 freed = FALSE;
  722.  
  723.     header = (NodeMemoryHeader *) (addr - sizeof(NodeMemoryHeader));
  724.  
  725. /*
  726.  * Here, the header may well not be valid.  It should not be for non-node
  727.  * objects.
  728.  */
  729.  
  730.     if (HeaderIsValid(header))
  731.     {
  732.         hash_position = NodeTableHash(header->size);
  733.         if (page_data->node_table[hash_position].used)
  734.         {
  735.             for (page = page_data->node_table[hash_position].first_page;
  736.                   page != NULL && !freed;
  737.                   page = page->next)
  738.             {
  739.                 if (page->begin_addr <= addr && page->end_addr > addr)
  740.                 {
  741.                     offset = (addr - page->begin_addr)
  742.                               / (page->element_size + sizeof(NodeMemoryHeader));
  743.  
  744.                     index = offset / BITS_IN_BYTE;
  745.                     bit = offset % BITS_IN_BYTE;
  746.  
  747.                     if (TEST_BIT(page->page_map[index], bit))
  748.                     {
  749.                         page->page_map[index] = UNSET_BIT(page->page_map[index],
  750.                                                           bit);
  751.                         page->ref_count -= 1;
  752.                         if (page->page_full) page->page_full = FALSE;
  753.                         if (page->ref_count == 0 && page->is_malloced == TRUE)
  754.                         {
  755.                             prev->next = page->next;
  756.                             free((char *)page);
  757.                         }
  758.                         else
  759.                         {
  760.                             header->debug_depth = 0;
  761.                             if (header < page->first_free_header
  762.                              || page->first_free_header == NULL)
  763.                             {
  764.                                 page->offset = offset;
  765.                                 page->first_free_header = header;
  766.                             }
  767.                         }
  768.                     }
  769.                     else
  770.                     {
  771.                         elog(NOTICE, "FreeNodeMemory: addr %x was already free",
  772.                              addr);
  773.                     }
  774.                     freed = TRUE;
  775.                 }
  776.                 prev = page;
  777.             }
  778.         }
  779.     }
  780.     return(freed);
  781. }
  782.  
  783. bool8
  784. FreeOtherMemory(addr)
  785.  
  786. unsigned char *addr;
  787.  
  788. {
  789.     OtherMemoryPage *page, *prev = NULL;
  790.     OtherMemoryHeader *header;
  791.     bool8 freed = FALSE;
  792.     int offset;
  793.  
  794.     for (page = page_data->other_pages;
  795.          page != NULL && !freed;
  796.          page = page->next)
  797.     {
  798.         if (page->begin_addr <= addr && page->end_addr > addr)
  799.         {
  800.             header = (OtherMemoryHeader *) (addr - sizeof(OtherMemoryHeader));
  801.             if (header->used)
  802.             {
  803.                 if (!HeaderIsValid(header))
  804.                 {
  805.                     other_memory_page_info(page);
  806.                     elog(WARN, "FreeOtherMemory - bad header at %x",header);
  807.                 }
  808.                 header->used = FALSE;
  809.                 header->debug_depth = 0;
  810.                 page->ref_count -= 1;
  811.                 if (page->page_full) page->page_full = FALSE;
  812.                 if (header->size > page->biggest_free_object)
  813.                     page->biggest_free_object = header->size;
  814.  
  815.                 if (page->first_free_header == NULL
  816.                  || header < page->first_free_header)
  817.                     page->first_free_header = header;
  818.  
  819.                 if (page->ref_count == 0 && page->is_malloced == TRUE)
  820.                 {
  821.                     prev->next = page->next;
  822.                     free((char *)page);
  823.                 }
  824.             }
  825.             else
  826.             {
  827.                 elog(NOTICE, "FreeOtherMemory: addr %x was already free", addr);
  828.             }
  829.             freed = TRUE;
  830.         }
  831.         prev = page;
  832.     }
  833.     return(freed);
  834. }
  835.  
  836. bool8
  837. FreeBigMemory(addr)
  838.  
  839. unsigned char *addr;
  840.  
  841. {
  842.     BigMemoryPage *page, *scanner;
  843.     bool8 freed = FALSE;
  844.     Size size = sizeof(BigMemoryPage) - sizeof(char *);
  845.  
  846.     printf("sizeof(BigMemoryPage) is %d\n", size);
  847.  
  848.     page = (BigMemoryPage *) ((long) addr - size);
  849.  
  850.     if (PageIsValid(page))
  851.     {
  852.         if (page == page_data->big_pages)
  853.         {
  854.             page_data->big_pages = page_data->big_pages->next;
  855.             free((char *)page);
  856.         }
  857.         else
  858.         {
  859.             for (scanner = page_data->big_pages;
  860.                  scanner->next != page;
  861.                  scanner = scanner->next);
  862.  
  863.             scanner->next = page->next;
  864.             free((char *)page);
  865.         }
  866.         freed = TRUE;
  867.     }
  868.     return(freed);
  869. }
  870.  
  871. /*
  872.  ********************
  873.  * UTILITY ROUTINES *
  874.  ********************
  875.  */
  876.  
  877. /*
  878.  * Finds a free element in the page map, and sets the page map for that
  879.  * element to one.
  880.  */
  881.  
  882. int
  883. SetElement(page_map)
  884.  
  885. unsigned char *page_map;
  886.  
  887. {
  888.     int i, j;
  889.  
  890.     for (i = 0; i < MAPSIZE && page_map[i] == FULL; i++);
  891.     for (j = 0; j < BITS_IN_BYTE && TEST_BIT(page_map[i], j); j++);
  892.     page_map[i] = SET_BIT(page_map[i], j);
  893.     return(BITS_IN_BYTE * i + j);
  894. }
  895.  
  896. /*
  897.  * LargestFreeObject returns the size of the largest free object in an
  898.  * OtherMemoryPage.  It assumes that page->first_free_object is really
  899.  * a free object, so it is up to the caller to make sure that this is
  900.  * the case.
  901.  */
  902.  
  903. Size
  904. LargestFreeObject(page)
  905.  
  906. OtherMemoryPage *page;
  907.  
  908. {
  909.     OtherMemoryHeader *scanner;
  910.     Size biggest_size = 0;
  911.  
  912.     for (scanner = page->first_free_header;
  913.          scanner <= page->last_header;
  914.          scanner = NextOtherHeader(scanner))
  915.     {
  916.         if (!HeaderIsValid(scanner))
  917.         {
  918.             other_memory_page_info(page);
  919.             elog(WARN, "GetOtherMemory: page corrupted!");
  920.         }
  921.         if (!scanner->used && scanner->size > biggest_size)
  922.             biggest_size = scanner->size;
  923.     }
  924.     return(biggest_size);
  925. }
  926.  
  927. SetNextFreeNode(page, offset)
  928.  
  929. NodeMemoryPage *page;
  930. long offset;
  931.  
  932. {
  933.     int major_index, minor_index, i, j;
  934.     long free_offset;
  935.     NodeMemoryHeader *header;
  936.  
  937.     if (page->ref_count == page->max_elements) return;
  938.  
  939.     major_index = offset / BITS_IN_BYTE;
  940.     minor_index = offset % BITS_IN_BYTE;
  941.  
  942.     for (i = major_index; page->page_map[i] == FULL; i++);
  943.     for (j = 0; TEST_BIT(page->page_map[i], j); j++);
  944.  
  945.     free_offset = i * BITS_IN_BYTE + j;
  946.  
  947.     header = (NodeMemoryHeader *)
  948.              ((long)
  949.              (page->begin_addr + free_offset
  950.               * (page->element_size + sizeof(NodeMemoryHeader))));
  951.  
  952.     if (HeaderIsValid(header))
  953.     {
  954.         page->first_free_header = header;
  955.         page->offset = free_offset;
  956.     }
  957.     else
  958.     {
  959.         elog(WARN, "SetNextFreeNode - %x bad header", header);
  960.     }
  961. }
  962.  
  963. /*
  964.  ***********************
  965.  * DEBUGGING FUNCTIONS *
  966.  ***********************
  967.  */
  968.  
  969. /*
  970.  * Debugging/tracing function.  Prints a summary of the information
  971.  * concerning an OtherMemoryPage.  
  972.  */
  973.  
  974. int
  975. other_memory_page_info(page)
  976.  
  977. OtherMemoryPage *page;
  978.  
  979. {
  980.     OtherMemoryHeader *header;
  981.     int i;
  982.  
  983.     printf("page base address is 0x%x\n", page->begin_addr);
  984.     printf("page usage summary...\n\n");
  985.     printf("page->ref_count is %d\n", page->ref_count);
  986.     printf("page->total is %d\n", page->total);
  987.     printf("page usage map is :\n\n");
  988.  
  989.     header = (OtherMemoryHeader *) page->begin_addr;
  990.     for (i = 0; i < page->total; i++)
  991.     {
  992.         printf("object %d: size %d isfree %s\n", i, header->size,
  993.             (header->used ? "false" : "true"));
  994.         if (!HeaderIsValid(header))
  995.             printf("header for object %d is INVALID", i);
  996.         if (header == page->first_free_header)
  997.             printf("page->first_free_header is set to object %d\n", i);
  998.         header = NextOtherHeader(header);
  999.     }
  1000.     return(0);
  1001. }
  1002.  
  1003. int
  1004. PushMemoryTraceLevel()
  1005.  
  1006. {
  1007.     if (!memory_tracing_mode) memory_tracing_mode = TRUE;
  1008.     if (trace_depth != 0xff)
  1009.     {
  1010.         trace_depth++;
  1011.         printf("PushMemoryTraceLevel(%d)\n", trace_depth);
  1012.     }
  1013.     else
  1014.         printf("PushMemoryTraceLevel: max trace levels reached.");
  1015. }
  1016.  
  1017. int
  1018. DumpMemoryTrace()
  1019.  
  1020. {
  1021.     DumpTrace(trace_depth);
  1022. }
  1023.  
  1024. int DumpAllTrace()
  1025.  
  1026. {
  1027.     DumpTrace(1);
  1028. }
  1029.  
  1030. bool8
  1031. FindCorruptedAddresses()
  1032.  
  1033. {
  1034. }
  1035.  
  1036. int
  1037. PopMemoryTraceLevel()
  1038. {
  1039.     if (trace_depth == 0)
  1040.     {
  1041.         printf("PopMemoryTraceLevel: not tracing\n");
  1042.     }
  1043.     else
  1044.     {
  1045.         printf("PopMemoryTraceLevel(%d)\n", trace_depth);
  1046.         trace_depth--;
  1047.         DecrementTraceLevel(trace_depth);
  1048.         if (trace_depth == 0) memory_tracing_mode = FALSE;
  1049.     }
  1050. }
  1051.  
  1052. DumpTrace(trace_depth)
  1053.  
  1054. uint8 trace_depth;
  1055.  
  1056. {
  1057.     NodeMemoryPage *node_page;
  1058.     NodeMemoryHeader *header;
  1059.     OtherMemoryPage *other_page;
  1060.     OtherMemoryHeader *oheader;
  1061.     int i, j, old_size = 0, element_count, small_count, large_count;
  1062.     char *type;
  1063.  
  1064.     printf("DumpTrace Memory Summary - trace level %d \n", trace_depth);
  1065.     for (i = 0; i < number_of_nodes; i++)
  1066.     {
  1067.         if (page_data->node_table[i].used)
  1068.         {
  1069.             for (node_page = page_data->node_table[i].first_page;
  1070.                  node_page != NULL;
  1071.                  node_page = node_page->next)
  1072.             {
  1073.                 element_count = 0;
  1074.                 for (header = (NodeMemoryHeader *) node_page->begin_addr, j = 0;
  1075.                      j < node_page->max_elements;
  1076.                      j++,
  1077.                      header = NextNodeHeader(header, node_page->element_size))
  1078.                 {
  1079.                     if (header->debug_depth >= trace_depth) element_count++;
  1080.                 }
  1081.                 if (element_count != 0)
  1082.                 {
  1083.                     printf("%d nodes of the following types were allocated\n",
  1084.                            element_count);
  1085.                     for (j = 0; j < page_data->node_table[i].node_count; j++)
  1086.                     {
  1087.                         printf("%s\n", page_data->node_table[i].names[j]);
  1088.                     }
  1089.                 }
  1090.             }
  1091.         }
  1092.     }
  1093.  
  1094.     small_count = 0;
  1095.     large_count = 0;
  1096.     for (other_page = page_data->other_pages;
  1097.          other_page != NULL;
  1098.          other_page = other_page->next)
  1099.     {
  1100.         for (oheader = (OtherMemoryHeader *) other_page->begin_addr;
  1101.              HeaderIsValid(oheader);
  1102.              oheader = NextOtherHeader(oheader))
  1103.         {
  1104.             if (oheader->debug_depth >= trace_depth)
  1105.             {
  1106.                 if (oheader->size < sizeof(HeapTuple) + PALLOC_HEADER_SIZE)
  1107.                 {
  1108.                     large_count++;
  1109.                 }
  1110.                 else
  1111.                 {
  1112.                     small_count++;
  1113.                 }
  1114.             }
  1115.         }
  1116.     }
  1117.  
  1118.     if (large_count == 0 && small_count == 0)
  1119.     {
  1120.         printf("No detectable non-nodes allocated.\n");
  1121.     }
  1122.     else 
  1123.     {
  1124.         if (large_count != 0)
  1125.         {
  1126.             printf("%d objects large enough to be tuples were allocated.\n",
  1127.                    large_count);
  1128.         }
  1129.         if (small_count != 0)
  1130.         {
  1131.             printf("%d small non-node objects were allocated.\n", small_count);
  1132.         }
  1133.     }
  1134. }
  1135.  
  1136. DecrementTraceLevel(trace_depth)
  1137.  
  1138. uint8 trace_depth;
  1139.  
  1140. {
  1141.     NodeMemoryPage *node_page;
  1142.     NodeMemoryHeader *header;
  1143.     OtherMemoryPage *other_page;
  1144.     OtherMemoryHeader *oheader;
  1145.     int i, j, old_size = 0, element_count, small_count, large_count;
  1146.     char *type;
  1147.  
  1148.     for (i = 0; i < number_of_nodes; i++)
  1149.     {
  1150.         if (page_data->node_table[i].used)
  1151.         {
  1152.             for (node_page = page_data->node_table[i].first_page;
  1153.                  node_page != NULL;
  1154.                  node_page = node_page->next)
  1155.             {
  1156.                 element_count = 0;
  1157.                 for (header = (NodeMemoryHeader *) node_page->begin_addr, j = 0;
  1158.                      j < node_page->max_elements;
  1159.                      j++,
  1160.                      header = NextNodeHeader(header, node_page->element_size))
  1161.                 {
  1162.                     if (header->debug_depth > trace_depth)
  1163.                         header->debug_depth = trace_depth;
  1164.                 }
  1165.             }
  1166.         }
  1167.     }
  1168.  
  1169.     for (other_page = page_data->other_pages;
  1170.          other_page != NULL;
  1171.          other_page = other_page->next)
  1172.     {
  1173.         for (oheader = (OtherMemoryHeader *) other_page->begin_addr;
  1174.              HeaderIsValid(oheader);
  1175.              oheader = NextOtherHeader(oheader))
  1176.         {
  1177.             if (oheader->debug_depth > trace_depth)
  1178.                 oheader->debug_depth = trace_depth;
  1179.         }
  1180.     }
  1181. }
  1182.